home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / edit / thesrc20.zip / sort.c < prev    next >
C/C++ Source or Header  |  1995-01-26  |  22KB  |  524 lines

  1. /***********************************************************************/
  2. /* SORT.C - Functions related to the SORT command.                     */
  3. /***********************************************************************/
  4. /*
  5.  * THE - The Hessling Editor. A text editor similar to VM/CMS xedit.
  6.  * Copyright (C) 1991-1995 Mark Hessling
  7.  *
  8.  * This program is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU General Public License as
  10.  * published by the Free Software Foundation; either version 2 of
  11.  * the License, or any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16.  * General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to:
  20.  *
  21.  *    The Free Software Foundation, Inc.
  22.  *    675 Mass Ave,
  23.  *    Cambridge, MA 02139 USA.
  24.  *
  25.  *
  26.  * If you make modifications to this software that you feel increases
  27.  * it usefulness for the rest of the community, please email the
  28.  * changes, enhancements, bug fixes as well as any and all ideas to me.
  29.  * This software is going to be maintained and enhanced as deemed
  30.  * necessary by the community.
  31.  *
  32.  * Mark Hessling                     email: M.Hessling@gu.edu.au
  33.  * 36 David Road                     Phone: +61 7 849 7731
  34.  * Holland Park                      Fax:   +61 7 875 5314
  35.  * QLD 4121
  36.  * Australia
  37.  */
  38.  
  39. /*
  40. $Id: SORT.C 2.0 1995/01/26 16:34:40 MH Release MH $
  41. */
  42.  
  43. #include <stdio.h>
  44.  
  45. #include "the.h"
  46. #include "proto.h"
  47.  
  48. #define MAX_SORT_FIELDS 10
  49.  
  50. #define SF_ERROR    0
  51. #define SF_START    1
  52. #define SF_ORDER    2
  53. #define SF_LEFT     3
  54.  
  55. struct sort_field
  56.  {
  57.   CHARTYPE order;                     /* A - ascending, D - descending */
  58.   LENGTHTYPE left_col;                                  /* left column */
  59.   LENGTHTYPE right_col;                                /* right column */
  60.  };
  61. typedef struct sort_field SORT_FIELD;
  62.  
  63. CHARTYPE *sort_field_1;
  64. CHARTYPE *sort_field_2;
  65.  
  66. SORT_FIELD sort_fields[MAX_SORT_FIELDS];
  67.  
  68. short num_fields;
  69.  
  70. #ifdef __STDC__
  71. static int cmp(const void *,const void *);
  72. #else
  73. static int cmp();
  74. #endif
  75.  
  76. /***********************************************************************/
  77. #ifdef __STDC__
  78. static int cmp(const void *first,const void *second)
  79. #else
  80. static int cmp(first,second)
  81. void *first,*second;
  82. #endif
  83. /***********************************************************************/
  84. {
  85. /*-------------------------- external data ----------------------------*/
  86. /*--------------------------- local data ------------------------------*/
  87.  register short i=0,j=0;
  88.  short len=0,rc=RC_OK;
  89.  LENGTHTYPE right_col=0,left_col=0;
  90.  LINE *one = *(LINE **)first;
  91.  LINE *two = *(LINE **)second;
  92. /*--------------------------- processing ------------------------------*/
  93. /*---------------------------------------------------------------------*/
  94. /* For each sort field defined in the array sort_fields, compare the   */
  95. /* value of both lines for the specified column range.                 */
  96. /*---------------------------------------------------------------------*/
  97.  for (i=0;i<num_fields;i++)
  98.     {
  99. /*---------------------------------------------------------------------*/
  100. /* Calculate the length of the sort field.                             */
  101. /*---------------------------------------------------------------------*/
  102.      len = sort_fields[i].right_col - sort_fields[i].left_col + 1;
  103. /*---------------------------------------------------------------------*/
  104. /* Set the two temporary fields to blanks.                             */
  105. /*---------------------------------------------------------------------*/
  106.      memset(sort_field_1,' ',len);
  107.      memset(sort_field_2,' ',len);
  108. /*---------------------------------------------------------------------*/
  109. /* For the first line to be compared, extract the portion of the line  */
  110. /* that corresponds with the current sort column...                    */
  111. /*---------------------------------------------------------------------*/
  112.      right_col = min(sort_fields[i].right_col,one->length);
  113.      left_col = min(sort_fields[i].left_col,one->length);
  114. /*---------------------------------------------------------------------*/
  115. /* If the sort column lies after the end of the line, leave the        */
  116. /* contents of the sort field blank.                                   */
  117. /*---------------------------------------------------------------------*/
  118.      if (sort_fields[i].left_col <= one->length)
  119.         memcpy(sort_field_1,one->line+left_col-1,right_col-left_col+1);
  120. /*---------------------------------------------------------------------*/
  121. /* For the next  line to be compared, extract the portion of the line  */
  122. /* that corresponds with the current sort column...                    */
  123. /*---------------------------------------------------------------------*/
  124.      right_col = min(sort_fields[i].right_col,two->length);
  125.      left_col = min(sort_fields[i].left_col,two->length);
  126. /*---------------------------------------------------------------------*/
  127. /* If the sort column lies after the end of the line, leave the        */
  128. /* contents of the sort field blank.                                   */
  129. /*---------------------------------------------------------------------*/
  130.      if (sort_fields[i].left_col <= two->length)
  131.         memcpy(sort_field_2,two->line+left_col-1,right_col-left_col+1);
  132. /*---------------------------------------------------------------------*/
  133. /* If CASE IGNORE is on for the current view, set both sort fields to  */
  134. /* uppercase for the comparison.                                       */
  135. /*---------------------------------------------------------------------*/
  136.      if (CURRENT_VIEW->case_sort == CASE_IGNORE)
  137.        {
  138.         for (j=0;j<len;j++)
  139.           {
  140.            if (islower(sort_field_1[j]))
  141.               sort_field_1[j] = toupper(sort_field_1[j]);
  142.            if (islower(sort_field_2[j]))
  143.               sort_field_2[j] = toupper(sort_field_2[j]);
  144.           }
  145.        }
  146. /*---------------------------------------------------------------------*/
  147. /* If the two sort fields are equal, continue the sort with the next   */
  148. /* sort field value. If the sort fields are different, return with the */
  149. /* the comparison value (if ASCENDING) or the comparison value negated */
  150. /* (if DESCENDING).                                                    */
  151. /*---------------------------------------------------------------------*/
  152.      if ((rc = strncmp(sort_field_1,sort_field_2,len)) != 0)
  153.         return((sort_fields[i].order == 'A') ? rc : -rc);
  154.     }
  155. /*---------------------------------------------------------------------*/
  156. /* To get to here, the result of sorting on all fields has resulted in */
  157. /* both lines being equal. Return with 0 to indicate this.             */
  158. /*---------------------------------------------------------------------*/
  159.  return(0);
  160. }
  161. /***********************************************************************/
  162. #ifdef PROTO
  163. short execute_sort(CHARTYPE *params)
  164. #else
  165. short execute_sort(params)
  166. #endif
  167. /***********************************************************************/
  168. {
  169. /*-------------------------- external data ----------------------------*/
  170.  extern bool in_profile;
  171.  extern CHARTYPE *temp_cmd;
  172.  extern VIEW_DETAILS *vd_mark;
  173. /*--------------------------- local data ------------------------------*/
  174. #define SOR_PARAMS  32
  175.  register int i=0;
  176.  CHARTYPE *word[SOR_PARAMS+1];
  177.  unsigned short num_params=0;
  178.  LINE **lfirst=NULL,**lp=NULL,*curr=NULL,*first=NULL,*last=NULL;
  179.  LINETYPE num_lines=0L,j=0L,true_line=0L,dest_line=0L;
  180.  short rc=RC_OK,direction=DIRECTION_FORWARD;
  181.  LENGTHTYPE left_col=0,right_col=0,max_column_width=0;
  182.  short state=0;
  183.  CHARTYPE order='A';
  184.  TARGET target;
  185.  short target_type=TARGET_NORMAL|TARGET_BLOCK_CURRENT|TARGET_ALL|TARGET_SPARE;
  186.  bool save_scope_all=FALSE;
  187. /*--------------------------- processing ------------------------------*/
  188. #ifdef TRACE
  189.  trace_function("sort.c:    execute_sort");
  190. #endif
  191. /*---------------------------------------------------------------------*/
  192. /* Save the current setting of scope_all to fool the validate_target() */
  193. /* routine into thinking scope_all is in effect.                       */
  194. /*---------------------------------------------------------------------*/
  195.  save_scope_all = CURRENT_VIEW->scope_all;
  196. /*---------------------------------------------------------------------*/
  197. /* Validate first argument as a target...                              */
  198. /*---------------------------------------------------------------------*/
  199.  initialise_target(&target);
  200.  rc = validate_target(params,&target,target_type,get_true_line(),TRUE,TRUE);
  201. /*---------------------------------------------------------------------*/
  202. /* Restore the setting of scope_all before anything else is done.      */
  203. /*---------------------------------------------------------------------*/
  204.  CURRENT_VIEW->scope_all = save_scope_all;
  205.  if (rc != RC_OK)
  206.    {
  207.     free_target(&target);
  208. #ifdef TRACE
  209.     trace_return();
  210. #endif
  211.     return(RC_INVALID_OPERAND);
  212.    }
  213.  true_line = target.true_line;
  214.  num_lines = target.num_lines;
  215.  dest_line = target.true_line + target.num_lines -1L;
  216.  direction = DIRECTION_FORWARD;
  217.  if (num_lines > 0L
  218.  &&  true_line == 0L)
  219.    {
  220.     true_line++;
  221.     num_lines--;
  222.    }
  223.  if (num_lines < 0L
  224.  &&  true_line == CURRENT_FILE->number_lines+1L)
  225.    {
  226.     true_line--;
  227.     num_lines++;
  228.    }
  229.  if (num_lines < 0L)
  230.    {
  231.     dest_line = target.true_line + target.num_lines +1L;
  232.     true_line = true_line + num_lines + 1L;
  233.     num_lines = num_lines * (-1L);
  234.     direction = DIRECTION_BACKWARD;
  235.    }
  236. /*---------------------------------------------------------------------*/
  237. /* Don't need to do anything if < 2 lines to be sorted.                */
  238. /*---------------------------------------------------------------------*/
  239.  if (num_lines < 2L)
  240.    {
  241.     free_target(&target);
  242.     display_error(55,(CHARTYPE *)"",FALSE);
  243. #ifdef TRACE
  244.     trace_return();
  245. #endif
  246.     return(RC_OK);
  247.    }
  248. /*---------------------------------------------------------------------*/
  249. /* Parse the remainder of the arguments and set up the sort_fields[]   */
  250. /* array with valid values.                                            */
  251. /*---------------------------------------------------------------------*/
  252.  if (target.spare != (-1))
  253.     num_params = param_split(strtrunc(target.rt[target.spare].string),word,SOR_PARAMS,WORD_DELIMS,TEMP_PARAM);
  254. /*---------------------------------------------------------------------*/
  255. /* Process parameters differently, depending on the number...          */
  256. /* 0 parameter (target only) - if BOX BLOCK, then the sort field will  */
  257. /*                             be the block columns, otherwise ZONE    */
  258. /*                             settings will be used.                  */
  259. /* 1 parameters (target & order) - same as above but also validate the */
  260. /*                                 ordering value.                     */
  261. /* > 1 parameters (target & sort fields) - validate each parameter.    */
  262. /*---------------------------------------------------------------------*/
  263.  switch(num_params)
  264.    {
  265.     case 0:
  266.     case 1:
  267.            sort_fields[0].left_col = CURRENT_VIEW->zone_start;
  268.            sort_fields[0].right_col = CURRENT_VIEW->zone_end;
  269.            sort_fields[0].order = order;
  270.            num_fields = 1;
  271.            if (target.rt[0].target_type == TARGET_BLOCK_CURRENT
  272.            && MARK_VIEW->mark_type == M_BOX)
  273.              {
  274.               sort_fields[0].left_col = MARK_VIEW->mark_start_col;
  275.               sort_fields[0].right_col = MARK_VIEW->mark_end_col;
  276.              }
  277. /*---------------------------------------------------------------------*/
  278. /* No more processing if only 1 parameter.                             */
  279. /*---------------------------------------------------------------------*/
  280.            if (num_params == 0)
  281.               break;
  282. /*---------------------------------------------------------------------*/
  283. /* Processing for 2 parameters; validate ordering value.               */
  284. /*---------------------------------------------------------------------*/
  285.            if (equal((CHARTYPE *)"ascending",word[0],1)
  286.            ||  equal((CHARTYPE *)"descending",word[0],1))
  287.              {
  288.               order = word[0][0];
  289.               if (islower(order))
  290.                  order = toupper(order);
  291.               sort_fields[0].order = order;
  292.               break;
  293.              }
  294. /*---------------------------------------------------------------------*/
  295. /* If the parameter is not Ascending or Descending, display error.     */
  296. /*---------------------------------------------------------------------*/
  297.            display_error(1,(CHARTYPE *)word[0],FALSE);
  298.            free_target(&target);
  299. #ifdef TRACE
  300.            trace_return();
  301. #endif
  302.            return(RC_INVALID_OPERAND);
  303.            break;
  304. /*---------------------------------------------------------------------*/
  305. /* More than 1 parameters; sort field(s) are being specified.          */
  306. /*---------------------------------------------------------------------*/
  307.     default:
  308.            i = 0;
  309.            num_fields = 0;
  310.            state = SF_START;
  311.            while(1)
  312.              {
  313.               switch(state)
  314.                 {
  315.                  case SF_START:
  316.                       if (equal((CHARTYPE *)"ascending",word[i],1)
  317.                       ||  equal((CHARTYPE *)"descending",word[i],1))
  318.                         {
  319.                          order = word[i][0];
  320.                          if (islower(order))
  321.                             order = toupper(order);
  322.                          sort_fields[num_fields].order = order;
  323.                          state = SF_ORDER;
  324.                          i++;
  325.                          break;
  326.                         }
  327.                       left_col = atoi(word[i]);
  328.                       if (left_col == 0)
  329.                         {
  330.                          state = SF_ERROR;
  331.                          break;
  332.                         }
  333.                       sort_fields[num_fields].order = order;
  334.                       sort_fields[num_fields].left_col = left_col;
  335.                       state = SF_LEFT;
  336.                       i++;
  337.                       break;
  338.                  case SF_ORDER:
  339.                       left_col = atoi(word[i]);
  340.                       if (left_col < 1)
  341.                         {
  342.                          state = SF_ERROR;
  343.                          break;
  344.                         }
  345.                       sort_fields[num_fields].left_col = left_col;
  346.                       state = SF_LEFT;
  347.                       i++;
  348.                       break;
  349.                  case SF_LEFT:
  350.                       right_col = atoi(word[i]);
  351.                       if (right_col < 1)
  352.                         {
  353.                          state = SF_ERROR;
  354.                          break;
  355.                         }
  356.                       sort_fields[num_fields].right_col = right_col;
  357.                       if (right_col < left_col)
  358.                         {
  359.                          state = SF_ERROR;
  360.                          break;
  361.                         }
  362.                       state = SF_START;
  363.                       i++;
  364.                       num_fields++;
  365.                       break;
  366.                  default:
  367.                       state = SF_ERROR;
  368.                       break;
  369.                 }
  370. /*---------------------------------------------------------------------*/
  371. /* If we have an error, display a message...                           */
  372. /*---------------------------------------------------------------------*/
  373.               if (state == SF_ERROR)
  374.                 {
  375.                  free_target(&target);
  376.                  display_error(1,(CHARTYPE *)word[i],FALSE);
  377. #ifdef TRACE
  378.                  trace_return();
  379. #endif
  380.                  return(RC_INVALID_OPERAND);
  381.                 }
  382. /*---------------------------------------------------------------------*/
  383. /* If we have run out of parameters...                                 */
  384. /*---------------------------------------------------------------------*/
  385.               if (i == num_params)
  386.                 {
  387. /*---------------------------------------------------------------------*/
  388. /* ...then if we have the correct number of parameters, OK.            */
  389. /*---------------------------------------------------------------------*/
  390.                  if (state == SF_START)
  391.                     break;
  392.                  else
  393. /*---------------------------------------------------------------------*/
  394. /* ...otherwise display an error.                                      */
  395. /*---------------------------------------------------------------------*/
  396.                    {
  397.                     free_target(&target);
  398.                     display_error(1,strtrunc(target.rt[target.spare].string),FALSE);
  399. #ifdef TRACE
  400.                     trace_return();
  401. #endif
  402.                     return(RC_INVALID_OPERAND);
  403.                    }
  404.                 }
  405.              }
  406.            break;
  407.    }
  408. /*---------------------------------------------------------------------*/
  409. /* Determine the maximum length of a sort field.                       */
  410. /*---------------------------------------------------------------------*/
  411.  for (i=0;i<num_fields;i++)
  412.     max_column_width = max(max_column_width,
  413.                 sort_fields[i].right_col - sort_fields[i].left_col + 1);
  414. /*---------------------------------------------------------------------*/
  415. /* Allocate memory for each of the temporary sort fields to the length */
  416. /* of the maximum field width.                                         */
  417. /*---------------------------------------------------------------------*/
  418.  if ((sort_field_1 = (CHARTYPE *)(*the_malloc)(max_column_width)) == NULL)
  419.    {
  420.     free_target(&target);
  421.     display_error(30,(CHARTYPE *)"",FALSE);
  422. #ifdef TRACE
  423.     trace_return();
  424. #endif
  425.     return(RC_OUT_OF_MEMORY);
  426.    }
  427.  if ((sort_field_2 = (CHARTYPE *)(*the_malloc)(max_column_width)) == NULL)
  428.    {
  429.     free_target(&target);
  430.     display_error(30,(CHARTYPE *)"",FALSE);
  431. #ifdef TRACE
  432.     trace_return();
  433. #endif
  434.     return(RC_OUT_OF_MEMORY);
  435.    }
  436. /*---------------------------------------------------------------------*/
  437. /* Assign the values of the newly allocated array to the LINE pointers */
  438. /* for the target lines.                                               */
  439. /*---------------------------------------------------------------------*/
  440.  first = curr = lll_find(CURRENT_FILE->first_line,true_line);
  441. #ifdef MSWIN
  442.  wqsort(curr,(long)num_lines,(int)sizeof(LINE *),cmp);
  443. #else
  444. /*---------------------------------------------------------------------*/
  445. /* Allocate memory for num_lines of LINE pointers.                     */
  446. /*---------------------------------------------------------------------*/
  447.  if ((lfirst = (LINE **)(*the_malloc)(num_lines*sizeof(LINE *))) == NULL)
  448.    {
  449.     free_target(&target);
  450.     display_error(30,(CHARTYPE *)"",FALSE);
  451. #ifdef TRACE
  452.     trace_return();
  453. #endif
  454.     return(RC_OUT_OF_MEMORY);
  455.    }
  456.  lp = lfirst;
  457.  for (j=0L;j<num_lines;j++)
  458.    {
  459.     lp[j] = curr;
  460.     curr = curr->next;
  461.    }
  462.  last = curr;
  463. /*---------------------------------------------------------------------*/
  464. /* Sort the target array...                                            */
  465. /*---------------------------------------------------------------------*/
  466.  qsort(lfirst,num_lines,sizeof(LINE *),cmp);
  467. /*---------------------------------------------------------------------*/
  468. /* Merge  the sorted array pointers into the linked list...            */
  469. /*---------------------------------------------------------------------*/
  470.  lp = lfirst;
  471.  first->prev->next = lp[0];
  472.  for (j=0L;j<num_lines;j++)
  473.    {
  474.     if (j == 0L)
  475.       {
  476.        lp[0]->prev = first->prev;
  477.        lp[0]->next = lp[1];
  478.       }
  479.     else
  480.        if (j == num_lines - 1L)
  481.          {
  482.           lp[num_lines-1]->next = last;
  483.           lp[num_lines-1]->prev = lp[num_lines-2L];
  484.           last->prev = lp[num_lines-1L];
  485.          }
  486.        else
  487.          {
  488.           lp[j]->next = lp[j+1L];
  489.           lp[j]->prev = lp[j-1L];
  490.          }
  491.    }
  492. #endif
  493. /*---------------------------------------------------------------------*/
  494. /* If STAY is OFF, change the current and focus lines by the number    */
  495. /* of lines calculated from the target.                                */
  496. /*---------------------------------------------------------------------*/
  497.  if (!CURRENT_VIEW->stay                                 /* stay is off */
  498.  &&  target.num_lines != 0L)
  499.     CURRENT_VIEW->focus_line = CURRENT_VIEW->current_line = find_next_in_scope(NULL,dest_line,direction);
  500. /*---------------------------------------------------------------------*/
  501. /* Free up the memory used for the sort fields and the target array.   */
  502. /*---------------------------------------------------------------------*/
  503.  (*the_free)(sort_field_1);
  504.  (*the_free)(sort_field_2);
  505.  (*the_free)(lfirst);
  506.  free_target(&target);
  507. /*---------------------------------------------------------------------*/
  508. /* Increment alteration count...                                       */
  509. /*---------------------------------------------------------------------*/
  510.  if ((rc = increment_alt(CURRENT_FILE)) != RC_OK)
  511.    {
  512. #ifdef TRACE
  513.     trace_return();
  514. #endif
  515.     return(rc);
  516.    }
  517.  sprintf(temp_cmd,"%ld line(s) sorted",num_lines);
  518.  display_error(0,temp_cmd,TRUE);
  519. #ifdef TRACE
  520.  trace_return();
  521. #endif
  522.  return(RC_OK);
  523. }
  524.